package pl.edu.agh.gp.nodes;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.jgap.InvalidConfigurationException;
import org.jgap.gp.CommandDynamicArity;
import org.jgap.gp.IGPProgram;
import org.jgap.gp.impl.GPConfiguration;
import org.jgap.gp.impl.ProgramChromosome;
import org.jgap.util.CloneException;
import org.jgap.util.ICloneable;
import pl.edu.agh.model.core.Price;

import java.util.List;
import java.util.Random;

public abstract class AbstractNode extends CommandDynamicArity implements ICloneable {
    private final String name;
    private final Class childType;

    public AbstractNode(final GPConfiguration a_conf, int initialArity, int maxArity, String name, Class childType)  throws InvalidConfigurationException {
        super(a_conf, initialArity,  1, maxArity, DoubleClass);
        this.name = name;
        this.childType = childType;
    }

    protected abstract double performMathCalculations(DescriptiveStatistics stats);
    protected abstract Object localClone() throws InvalidConfigurationException;

    @Override
    public double execute_double(ProgramChromosome c, int n, Object[] args) {
        DescriptiveStatistics stats = new DescriptiveStatistics();

        if(childType.equals(DoubleClass)){
            int size = size();
            for (int i = 0; i < size; i++) {
                stats.addValue(c.execute_double(n, i, args));
            }
        }else if(childType.equals(List.class)){
            List<Price> prices = (List<Price>) c.execute_object(n, 0, args);
            if(prices == null || prices.size() == 0){
                throw new IllegalStateException("Prices list should be filled.");
            }

            for(Price price: prices){
                stats.addValue(price.getClose());
            }
        }
        return performMathCalculations(stats);
    }

    public Class getChildType(IGPProgram a_ind, int a_chromNum) {
        if(childType.equals(DoubleClass)){
            return childType;
        }else if(childType.equals(List.class) && a_chromNum == 0){
            return childType;
        }
        return VoidClass;
    }

    @Override
    public String toString() {
        String s = name + "(";
        int size = size();
        for (int i = 0; i < size; i++) {
            if (i > 0) {
                s += ";";
            }
            s += "&" + (i + 1);
        }
        return s + ")";
    }

    @Override
    public Object clone() {
        try {
            return localClone();
        } catch (Exception ex) {
            throw new CloneException(ex);
        }
    }
}
